home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / pascal / miscuni.com / PRNUTIL.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1989-05-25  |  18.2 KB  |  643 lines

  1. {.he Printer Utilities Module - %F}
  2. (**********************************************************************)
  3. (*                        Unit PrnUtil                                *)
  4. (*                                                                    *)
  5. (*                                                                    *)
  6. (*  Author:  Geoffrey W. Moehrke                                      *)
  7. (*  Date:  May 24, 1989                                               *)
  8. (*                                                                    *)
  9. (*  Purpose:  Low & high level printer handling.  Routines to handle  *)
  10. (*            printer response and user cancel as well as pagination, *)
  11. (*            and formatted headings & footers.                       *)
  12. (*                                                                    *)
  13. (*  Source: F:\TP\UNIT\PRNUTIL.PAS                                    *)
  14. (**********************************************************************)
  15. Unit PrnUtil;
  16.  
  17. Interface
  18.  
  19.   Uses
  20.     Dos,
  21.     TPCRT,
  22.     TPDate,
  23.     Messages,
  24.     TPString,
  25.     IOError
  26.  
  27.     {$IFDEF NetPrint},
  28.     DataEntry,
  29.     NetWare
  30.     {$ENDIF};
  31.  
  32.   const
  33.     MaxLineLength = 132;                   { Max length of printable strings           }
  34.  
  35.     PrnDatePic : DateString = 'mm/dd/yy';  { Defines format of time in headers/footers }
  36.     PrnTimePic : DateString = 'hh:mm te';  { Defines format of date in headers/footers }
  37.  
  38.   type
  39.     PageLine = String[MaxLineLength];
  40.     Justtype = (Left, Right, Middle);
  41.  
  42.   var
  43.     PrnStatus,                   { Printer status.                            }
  44.     PrnPort : Byte;              { Printer Port. 0 - LPT1, 1 - LPT2...        }
  45.     PrnCanceled: Boolean;        { True if print was interrupted, will not
  46.                                    print when this is true                    }
  47.     PrintToFile : Boolean;       { True if printing to disk file - must be
  48.                                    assigned & opened outside of this unit     }
  49.     PrnIOResult : Word;          { I/O result when printing to disk file.     }
  50.     PrnFile : Text;              { File to print to - must be assigned, and
  51.                                    rewritten outside this unit.               }
  52.     CurrLine : byte;             { Current line on page                       }
  53.     CurrPage : Word;             { Current page number                        }
  54.  
  55.     { The following vars are initialized to reasonable values but may be      }
  56.     { changed by calling program to customize behavior of this unit           }
  57.  
  58.     PageLength,                  { Number of lines/page                       }
  59.     PageWidth : Byte;            { Number of columns/page                     }
  60.     FootingLine : Byte;          { Line number to place footing on            }
  61.  
  62.     PrnInFileName : String[64];  { Used by Percent Expand for %F must be set  }
  63.                                  { by calling program                         }
  64.  
  65.     PrnErrorAttr : Byte;         { Attribute for message windows              }
  66.  
  67.     {$IFDEF NetPrint}
  68.     NetOK,                       { True if novell drivers initialized and  }
  69.                                  { user is logged in                       }
  70.     Capturing : boolean;         { True while printing is being spooled to }
  71.                                  { a network printer                       }
  72.     {$ENDIF}
  73.  
  74.   procedure Print(St : PageLine);
  75.     {-Print a string to printer or disk file, No CRLF following }
  76.  
  77.   procedure PrintLn(St : PageLine);
  78.     {-Print a string + CR + LF to printer or disk file }
  79.  
  80.   function PercentExpand( S: String ): String;
  81.     {- Expand Headings and footers using embedded % commands. The
  82.        following commands are implemented:
  83.  
  84.         %F - Replace with PrnInfileName which must be initialized by
  85.              the calling program.
  86.         %# - Replace with current page number.
  87.         %T - Replace with system time (formatted by PrnTimePic).
  88.         %D - Replace with system date (Formatted by PrnDatePic).
  89.         %< - Left justify entire line.
  90.         %> - Right justify entire line (dependent on PageWidth).
  91.         %[ - Alternate Left justify Even/Odd pages
  92.         %] - Alternate Right justify Even/Odd pages                  }
  93.  
  94.  
  95.   procedure PrintJust(Line : PageLine;Just:Justtype);
  96.     {-Print a justified or centered string }
  97.  
  98.   procedure PrnSkiplines(Num : Integer);
  99.     {-Skip Num lines }
  100.  
  101.   procedure NewPage(Footer : PageLine);
  102.     {-Advance to the top of the next page, printing Footer if desired}
  103.  
  104.   procedure PrnReset;
  105.     {-Reset to page1, line1}
  106.  
  107.   procedure InitPrinter;
  108.     {-Send reset to printer port.}
  109.  
  110.   function OpenPrnFile(FName: String): boolean;
  111.     {-Open print file }
  112.  
  113.   function ClosePrnFile(FName: String): boolean;
  114.     {-Close print file }
  115.  
  116.   {$IFDEF NetPrint}
  117.   function SetCapture( On: boolean ): boolean;
  118.     { Start or end capturing to a network printer }
  119.  
  120.   procedure SetPrintOptions;
  121.     { Set network print options for local/network toggle and printer number }
  122.   {$ENDIF}
  123.  
  124. Implementation
  125.  
  126.   const
  127.     MaxPortNum  = 2;
  128.  
  129.     PrnTimeOut  = $01;
  130.     PrnIOError  = $08;
  131.     PrnOnLine   = $10;
  132.     PrnOutPaper = $20;
  133.     PrnACK      = $40;
  134.     PrnNotBusy  = $80;
  135.  
  136.  
  137.   function GetPortStatus( PortNo : byte ): byte;
  138.  
  139.     var
  140.       Reg : registers;
  141.  
  142.     begin { GetPortStatus }
  143.       if ( PortNo > MaxPortNum ) then     { Invalid port num }
  144.          Exit;
  145.       with Reg do
  146.         begin
  147.           AH := 2;
  148.           DX := PortNo;
  149.           Intr($17,Reg);
  150.           GetPortStatus := AH
  151.         end
  152.     end;        { GetPortStatus }
  153.  
  154.  
  155.   function PrinterOnLine( Status : Byte ) : Boolean;
  156.    {-Checks PrnStatus to see if printer is ready }
  157.  
  158.     begin
  159.       PrinterOnLine := (Status <> 0) And ((Status And
  160.         (PrnTimeOut + PrnIOError + PrnOutPaper)) = 0);
  161.     end;
  162.  
  163.  
  164.   function Byte2Port( PortNum, TheByte : byte ) : byte;
  165.     {-Send a byte to port PortNum (0..MaxPortNum) returns status byte }
  166.  
  167.     var
  168.       Reg : registers;
  169.       Stat : Byte;
  170.  
  171.     begin { Byte2Port }
  172.       if (PortNum > MaxPortNum) then     { Invalid port num }
  173.          Exit;
  174.       repeat
  175.         Stat := GetPortStatus( PortNum );
  176.         if Not PrinterOnLine(Stat) then begin
  177.           Byte2Port := Stat;
  178.           exit
  179.         end;
  180.       until ((Stat and PrnNotBusy) <> 0);
  181.       with Reg do
  182.         begin
  183.       AH := 0;
  184.       AL := TheByte;
  185.       DX := PortNum;
  186.       Intr($17,Reg);
  187.       Byte2Port := AH
  188.         end
  189.     end;    { Byte2Port }
  190.  
  191.  
  192.   function InitPort( PortNum : byte ): byte;
  193.  
  194.     var
  195.       Regs : registers;
  196.  
  197.     begin { InitPort }
  198.       if (PortNum > MaxPortNum) then     { Invalid Port num }
  199.          Exit;
  200.       with Regs do
  201.         begin
  202.       AH := 1;
  203.       DX := PortNum;
  204.       Intr($17,Regs);
  205.       InitPort := AH
  206.         end
  207.      end;    { InitPort }
  208.  
  209.  
  210.   function StatusStr: String;
  211.     {-Returns error message based on Status byte }
  212.  
  213.     const
  214.       PStr = 'Printer';
  215.  
  216.     begin
  217.       StatusStr := '';
  218.       If ((PrnStatus And PrnIOError) <> 0) Then
  219.         StatusStr := PStr + ' error';
  220.       If ((PrnStatus And PrnACK) = 0) Then
  221.         StatusStr := PStr + ' is not ready';
  222.       If ((PrnStatus And PrnTimeOut) <> 0) Then
  223.         StatusStr := PStr + ' is not ready';
  224.       If ((PrnStatus And PrnNotBusy) = 0) Then
  225.         StatusStr := PStr + ' is not ready';
  226.       If ((PrnStatus And PrnOutPaper) <> 0) Then
  227.         StatusStr := PStr + ' is out of paper';
  228.       If ((PrnStatus And PrnOnLine) <> 0) Then
  229.         StatusStr := PStr + ' is not responding';
  230.     end;
  231.  
  232.  
  233.   function PrnTimeOutCancel: Boolean;
  234.     {-Pauses if printer error, cancels print if user enters ESC }
  235.  
  236.     const
  237.       ReadyPrompt = 'Please ready printer or press ESC to exit';
  238.  
  239.     var
  240.       Ch : Char;
  241.       Savedvar : boolean;
  242.  
  243.     begin
  244.       PrnTimeOutCancel := False;
  245.       If PrinterOnLine( PrnStatus ) Then Exit;
  246.       Savedvar := MsgDisposeCh;
  247.       MsgDisposeCh := False;
  248.       Message(TitleCmd+BeepCmd + LeaveCmd +' Printer Error '+TitleCmd +
  249.                 StatusStr + NewLnCmd + ReadyPrompt);
  250.       repeat
  251.         If KeyPressed Then
  252.           Ch := ReadKey;
  253.         PrnStatus := GetPortStatus( PrnPort );
  254.       until PrinterOnLine( PrnStatus ) or (Ch = #27);
  255.       RemoveMsg;
  256.       if Ch = #27 Then
  257.         PrnTimeOutCancel := True;
  258.       MsgDisposeCh := Savedvar;
  259.     end;
  260.  
  261.  
  262.   function PrnUserCancel : Boolean;
  263.     {-Pauses when user presses key, cancels if followed by ESC }
  264.  
  265.     const
  266.       UserPausePrompt1 = 'Printing Paused.  Press ESC to cancel or';
  267.       UserPausePrompt2 = 'any other key to resume...';
  268.  
  269.     var Ch : Char;
  270.         OldCursor : Word;
  271.         Savevar : boolean;
  272.  
  273.     begin
  274.       PrnUserCancel := False;
  275.       If Keypressed Then
  276.        begin
  277.          Ch := ReadKey;
  278.          Savevar := MsgDisposeCh;
  279.          MsgDisposeCh := False;
  280.          Message(TitleCmd+BeepCmd + PauseCmd +' Printer ' + TitleCmd +
  281.                  UserPausePrompt1 + NewLnCmd + UserPausePrompt2);
  282.          Ch := ReadKey;
  283.          MsgDisposeCh := Savevar;
  284.          If Ch = #27 Then
  285.            begin
  286.              PrnUserCancel := True;
  287.              PrnCanceled := True;
  288.            end;
  289.        end
  290.     end;
  291.  
  292.  
  293.   procedure CheckIOResult;
  294.     {-Checks I/O result of printing to a disk file }
  295.   begin
  296.     PrnIOResult := IOResult;
  297.     If PrnIOResult <> 0 Then
  298.       PrnCanceled := True;
  299.   end;
  300.  
  301.  
  302.   function PrnCancel:Boolean;
  303.     {-Checks printer and keyboard for any potential cancellation conditions }
  304.  
  305.     var
  306.       Ok : byte;
  307.  
  308.     begin
  309.       PrnCancel := False;
  310.       If PrnCanceled Then
  311.         begin
  312.           PrnCancel := True;
  313.           Exit;
  314.         end;
  315.       If PrnTimeOutCancel Then
  316.         begin
  317.           PrnCancel := True;
  318.           PrnCanceled := True;
  319.         end
  320.       Else
  321.         If KeyPressed And PrnUserCancel Then
  322.            begin
  323.              PrnCancel := True;
  324.              PrnCanceled := True;
  325.              If PrintToFile Then begin
  326.                 {$I-}
  327.                 Write(PrnFile,#12);
  328.                 {$I+}
  329.                 CheckIOResult;
  330.               end
  331.             Else begin
  332.               PrnStatus := Byte2Port( PrnPort,12 ); { Sent FF to printer }
  333.  
  334.               {$IFDEF NetPrint}
  335.               if NetOK And Capturing then begin
  336.                 Ok := CancelLPTCapture;
  337.                 if Ok <> 0 then
  338.                   Message(TitleCmd+PauseCmd+' < Error >'+TitleCmd+
  339.                           'Error canceling network print job.');
  340.               end;
  341.               {$ENDIF}
  342.  
  343.              end
  344.            end
  345.     end;
  346.  
  347.  
  348.   procedure Print(St : PageLine);
  349.     {-Print a string to printer or disk file }
  350.  
  351.     var
  352.       I : Byte;
  353.  
  354.     begin
  355.       If PrnCanceled Then Exit;
  356.       PrnStatus := GetPortStatus( PrnPort );
  357.       For I := 1 to Length(St) Do
  358.         begin
  359.           If PrnCancel Then Exit;
  360.             If PrintToFile Then begin
  361.               {$I-}
  362.               Write(PrnFile,St[I]);
  363.               {$I+}
  364.               CheckIOResult;
  365.             end
  366.           Else
  367.             PrnStatus := Byte2Port( PrnPort, Byte(St[I]) );
  368.        end;
  369.     end;
  370.  
  371.  
  372.   procedure PrintLn(St : PageLine);
  373.     {-Print a string + CR + LF to printer or disk file }
  374.  
  375.     const
  376.       CRLF = #13#10;
  377.     var
  378.       I : Byte;
  379.  
  380.     begin
  381.       If PrnCanceled Then Exit;
  382.       Print(St);
  383.       Print(CRLF);
  384.       Inc(CurrLine);
  385.       If CurrLine > PageLength Then
  386.         begin
  387.           CurrLine := 1;
  388.           CurrPage := CurrPage+1;
  389.         end;
  390.     end;
  391.  
  392.  
  393.   function PercentExpand( S: String ): String;
  394.     {- Expand Headings            }
  395.     var
  396.       PE: String;
  397.       I,CPN: Integer;
  398.       PN: String[6];
  399.       CurrJust : Justtype;
  400.  
  401.   begin
  402.     CurrJust := Middle;
  403.     PE := '';
  404.     I := 1;
  405.     while ( I<=Length(S) ) do
  406.       begin
  407.         if S[I]<>'%' then
  408.           PE:=PE+S[I]
  409.         else if I=Length(S) then
  410.           PE:=PE+'%'
  411.         else begin
  412.           Case UpCase(S[I+1]) Of
  413.              '#': begin                           { Insert Page Number      }
  414.                     PN := Long2Str(CurrPage);
  415.                     PE := PE+PN;
  416.                   end;
  417.              'T': PE := PE+CurrentTimeString(PrnTimePic);
  418.                                                   { Insert Time             }
  419.              'D': PE := PE+TodayString(PrnDatePic);
  420.                                                   { Insert Date             }
  421.              'F': PE := PE+PrnInFileName;         { Insert File Name        }
  422.              '<': CurrJust := Left;               { Left Justify Heading    }
  423.              '>': CurrJust := Right;              { Right Justify Heading   }
  424.              '[': if Odd(CurrPage) then           { Alternate Left Even/Odd }
  425.                      CurrJust := Left
  426.                   else CurrJust := Right;
  427.              ']': if Odd(CurrPage) then           { Alternate Right Even/Odd}
  428.                     CurrJust := Right
  429.                    else CurrJust := Left;
  430.               else PE:=PE+S[I+1];                 { Don't recognize         }
  431.           end; { Case S[I+1] }
  432.             I := I+1;
  433.         end; { Else S[I]='%' }
  434.         I := I+1;
  435.     end; { while }
  436.     Case CurrJust of
  437.       Middle : PE := Center (PE, PageWidth);
  438.       Left   : PE := Pad    (PE, PageWidth);
  439.       Right  : PE := LeftPad(PE,PageWidth);
  440.     end; { Case }
  441.     if Length(PE) > PageWidth then
  442.       PE[0] := Chr(PageWidth);
  443.     PercentExpand := PE;
  444.   end; { PercentExpand }
  445.  
  446.  
  447.   procedure PrintJust(Line : PageLine;Just:Justtype);
  448.     {-Print a justified or centered string }
  449.   var I : Byte;
  450.   begin
  451.     If PrnCanceled Then Exit;
  452.     Case Just Of
  453.       Middle : Println( Center (Line,PageWidth));
  454.       Left   : Println( Pad    (Line,PageWidth));
  455.       Right  : Println( LeftPad(Line,PageWidth));
  456.     end
  457.   end;
  458.  
  459.  
  460.   procedure PrnSkiplines(Num : Integer);
  461.     {-Skip Num lines }
  462.   var I : Integer;
  463.   begin
  464.     If PrnCanceled Then Exit;
  465.     For I := 1 To Num Do
  466.       PrintLn('');
  467.   end;
  468.  
  469.   procedure NewPage(Footer : PageLine);
  470.     {-Advance to the top of the next page, printing Footer if desired}
  471.   begin
  472.     If PrnCanceled Then Exit;
  473.     If (Footer = '') and (CurrLine = 1) then Exit;
  474.     While Currline < FootingLine Do
  475.       Println('');
  476.     PrintLn( PercentExpand(Footer) );
  477.     Repeat;
  478.       PrintLn('')
  479.     Until CurrLine = 1;
  480.   end;
  481.  
  482.  
  483.   procedure PrnReset;
  484.     {-Reset to page1, line1}
  485.   begin
  486.     CurrPage := 1;
  487.     CurrLine := 1;
  488.     PrnCanceled := False;
  489.   end;
  490.  
  491.   procedure InitPrinter;
  492.     {-Send reset to PRN port}
  493.   begin
  494.     PrnStatus := InitPort( PrnPort );
  495.   end;
  496.  
  497.   function OpenPrnFile(FName : String): boolean;
  498.  
  499.     var Result : Word;
  500.         Ch : Char;
  501.         Holdvar : Boolean;
  502.  
  503.     label Retry;
  504.  
  505.     begin
  506.       OpenprnFile := False;
  507.       PrintToFile := True;
  508.       Holdvar := MsgDisposeCh;
  509.       MsgDisposeCh := False;
  510.      Retry:
  511.       Assign(PrnFile,FNAme);
  512.       {$I-}
  513.       ReWrite(PrnFile);
  514.       {$I+}
  515.       Result := IOResult;
  516.       If Result <> 0 Then
  517.         begin
  518.           Message(TitleCmd + BeepCmd + PauseCmd  + TitleCmd +
  519.                   'Error: '+StUpCase(FName)+' - '+IOErrorMsg( Result ) +
  520.                   NewLnCmd +
  521.                   'Press ESC to Cancel, any other key to retry');
  522.           Ch := Readkey;
  523.           If Ch = #27 then
  524.             begin
  525.               PrnCanceled := True;
  526.               PrintToFile := False;
  527.               OpenPrnFile := False;
  528.               MsgDisposeCh := Holdvar;
  529.               Exit;
  530.             end;
  531.           Goto Retry;
  532.         end
  533.        else
  534.          OpenPrnFile := True;
  535.        MsgDisposeCh := Holdvar;
  536.      end;
  537.  
  538.   function ClosePrnFile( FName: String ): boolean;
  539.  
  540.    var Ch : Char;
  541.        Result : Word;
  542.  
  543.    label Retry;
  544.  
  545.    begin
  546.      If PrnCanceled then Exit;
  547.      PrintToFile := False;
  548.    Retry:
  549.      {$I-}
  550.      Close(PrnFile);
  551.      {$I+}
  552.      Result := IOResult;
  553.      If Result <> 0 Then
  554.        begin
  555.          Message(TitleCmd + BeepCmd + PauseCmd  + TitleCmd +
  556.                  'Error: '+StUpCase(FName)+' - '+IOErrorMsg(Result) +
  557.                  NewLnCmd +
  558.                  'Press ESC to Cancel, any other key to retry');
  559.          Ch := Readkey;
  560.          If Ch = #27 then
  561.            begin
  562.              PrnCanceled := True;
  563.              ClosePrnFile := False;
  564.              Exit;
  565.            end;
  566.          Goto Retry;
  567.        end
  568.      else
  569.        ClosePrnFile := True;
  570.    end;
  571.  
  572.   {$IFDEF NetPrint}
  573.   function SetCapture( On : Boolean ): boolean;
  574.  
  575.     begin
  576.       if Not NetOk then
  577.         exit;
  578.       If On And ( StartLPTCapture = 0 ) then
  579.         Capturing := True;
  580.       If Not On And (endLPTCapture = 0) then
  581.         Capturing := False;
  582.       SetCapture := ( Capturing = On )
  583.     end;
  584.  
  585.   procedure SetPrintOptions;
  586.  
  587.     var
  588.       Job : PrintJobtype;
  589.       SpoolNet : boolean;
  590.  
  591.     begin
  592.       if Not NetOK then
  593.         exit;
  594.       GetPrintJobFlags( Job );
  595.       SpoolNet := False;
  596.       DefineField( 1, 'Spool to Network Printer: ',DE_Y, 1, 0, 0, 0, 1, @SpoolNet);
  597.       DefineField( 2, '  Network Printer Number: ',DE_B,1, 0, 0, 2, 1, @Job.ServerPrinter);
  598.       DefinedFlds := 2;
  599.       if DataGet('Select Print Options (F2 when finished)', True, DefUsrFunc ) then
  600.         begin
  601.           SetPrintJobFlags( Job );
  602.           if SpoolNet then begin
  603.             if Capturing then
  604.              if SetCapture( False ) then ;
  605.             if Not SetCapture( True ) then
  606.                 Message(TitleCmd+PauseCmd+'< Error >'+TitleCmd+
  607.                         'Unable to spool to network printer');
  608.           end
  609.         end
  610.       else
  611.         PrnCanceled := True;
  612.       UndefineField(1);
  613.       UndefineField(2);
  614.       DefinedFlds := 0;
  615.     end;
  616.  
  617.    var
  618.      InitJob : PrintJobtype;
  619.      LoggedIn : Boolean;
  620.   {$ENDIF}
  621.  
  622. begin    { Initialize PrnUtil Unit }
  623.    {$IFDEF NetPrint}
  624.   if NetWareLoaded( LoggedIn ) then
  625.     NetOK := LoggedIn
  626.   else
  627.     NetOk := False;
  628.   if NetOK then begin
  629.     GetPrintJobFlags( InitJob );
  630.     if InitJob.Status=0 then
  631.       Capturing := True;
  632.   end;
  633.   {$ENDIF}
  634.   PrnIOResult := 0;
  635.   PrintToFile := False;
  636.   PrnPort := 0;
  637.   PrnStatus := GetPortStatus( PrnPort );
  638.   PageLength := 66;
  639.   PageWidth := 80;
  640.   FootingLine := PageLength - 1;
  641.   PrnReset;
  642. end.   { PrnUtil }
  643.